package com.ncu.spring;

import com.ncu.spring.anno.*;
import com.ncu.spring.aop.AnnotationAwareAspectJAutoProxyCreator;
import com.ncu.spring.aop.proxy.LazyInjectTargetSource;
import com.ncu.spring.aop.proxy.ProxyFactory;
import com.ncu.spring.interfaces.*;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.*;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 容器启动
 * BeanDefinition 扫描
 * Bean的生命周期
 * 单例与多例Bean
 * 依赖注入
 * AOP
 * Aware回调
 * 初始化
 * BeanPostProcessor
 */

// 疑问：为什么这么多Map 只有三级缓存 没有使用ConcurrentHashMap？
/*
    AbstractBeanFactory类下的doGetBean方法中使用的getSingleton() 来获取缓存中的对象 然后最终走到下面这个类的
    DefaultSingletonBeanRegistry 这个类 getSingleton() 方法 可以看出 使用了两次判断+synchronized保证多线程安全
    所以在三级缓存就不需要保证线程安全
 */
// 为什么要用synchronized而不直接用ConcurrentHashMap来保证线程安全呢？
/*
    二级缓存put的同时要保证三级缓存remove；三级缓存put时要保证二级缓存remove，也就是说二三级缓存操作要保证原子性
 */
//https://blog.csdn.net/weixin_43901882/article/details/120069307  3.2有讲解
public class ApplicationContext {  //容器对象

    //通过该类上方的@Component获取需要扫描的包
    private final Class<?> configClass;

    /**
     * beanName -> BeanDefinition
     * 存储的是Bean对象的 Definition 以便后续创建Bean对象  Key：beanName Value:BeanDefinition
     */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    /**
     * Cache of singleton factories: bean name to ObjectFactory.
     * Spring 的三级缓存 Key：beanName Value: 该bean的工厂对象
     * 因为三级缓存的使用场景是 在对象创建之后 依赖注入之前 将工厂对象放入三级缓存
     * 三级缓存的作用：解决代理对象的循环依赖问题
     */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    /**
     * Cache of early singleton objects: bean name to bean instance.
     * 二级缓存：用于中间存储。如果发生循环依赖，存储的就是代理对象，否者存储的就是原对象
     */
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

    /**
     * 单例池： beanName -> beanObj
     * 一级缓存: 限制bean只在BeanFactory中
     */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /**
     * Disposable bean instances: bean name to disposable instance.
     * 收集可销毁的Bean对象
     */
    private final Map<String, Object> disposableBeans = new LinkedHashMap<>();

    /**
     * Names of beans that are currently in creation.
     * 一个缓存 这个缓存存放了当前正在创建的对象 防止了bean对象在循环引用的过程中重复创建的问题。
     * 会用来判断在即将创建单例bean是否处于 :未创建完成 却又要创建
     * https://blog.csdn.net/qq_34116044/article/details/121532898  详解参考
     */
    private final Set<String> singletonsCurrentlyInCreation =
            Collections.newSetFromMap(new ConcurrentHashMap<>(16));

    /**
     * Names of Prototype beans that are currently in creation.
     * 这个变量用来记录当前正在创建的bean  这个是用来记录多例Bean是否正在创建
     * 通过ThreadLocal 对其进行保护
     * https://blog.csdn.net/lkp_kapila/article/details/105344252
     */
    private final ThreadLocal<Object> prototypesCurrentlyInCreation = new ThreadLocal<>();
    //收集bean后处理器
    private final List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();

    public ApplicationContext(Class<?> configClass) {
        this.configClass = configClass;
        scanBeanDefinition(configClass);
        registerBeanPostProcessors();
        preInstantiateSingletons();
    }

    /**
     * 扫描 -> 得到一系列 BeanDefinition，放入 beanDefinitionMap
     * 通过@ComponentScan 获取路径 -> 获取绝对路径 -> 通过File类去遍历 该目录下的文件(只遍历一层)
     * 将所有.class结尾的文件并且被@Component注解修饰类创建BeanDefination：
     *  1.判断@Component注解的value属性是否有值？有，就用这个做beanName,没有就用类名做为beanName
     *  2.生成beanDefinition对象 并且判断其为单例bean 还是多例bean
     *      singleton（单例）：只有一个共享的实例存在，所有对这个bean的请求都会返回这个唯一的实例。不管new多少次，只生成一个对象。
     *      prototype（多例）：对这个bean的每次请求都会创建一个新的bean实例，类似于new。
     *  3.最终 将beanDefinition 放入Map集合中
     */
    private void scanBeanDefinition(Class<?> configClass) {
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            // 扫描路径 com.ncu.test
            String path = componentScanAnnotation.value();
            // 扫描路径 com/ncu/test
            path = path.replace(".", "/");

            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            // 取得绝对路径: C:\Users\86157\IdeaProjects\Spring-impl\src\com\ncu\test
            URL resource = classLoader.getResource(path);
            File file = new File(resource.getFile());

            // 遍历目录下的所有文件，都是 componentScan 需要扫描的，这里只遍历了一层目录 即当前目录,子目录都没扫
            if (file.isDirectory()) {
                for (File f : file.listFiles()) { //返回的是该目录中的文件和目录。
                    String fileName = f.getAbsolutePath();
                    //System.out.println(fileName);  //输出该文件的绝对路径

                    if (fileName.endsWith(".class")) {
                        // 提取出 class 对象，需要类的全限定名
                        // com/ncu/test/Usertest
                        String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
                        // com.ncu.test.Usertest
                        className = className.replace(File.separator, ".");
                        //System.out.println(className);扫描过的类名
                        try {
                            //通过当前线程的类加载器+全限定名称 加载类
                            Class<?> cls = classLoader.loadClass(className);
                            // 当前 class 是个 Bean 对象
                            if (cls.isAnnotationPresent(Component.class)) { //类的上方是不是有Component注解
                                Component componentAnno = cls.getAnnotation(Component.class);
                                String beanName = componentAnno.value(); //获取这个bean的名称
                                //如果注解上方没有给value赋值 就生成默认的beanName
                                if ("".equals(beanName)) {
                                    //cls.getSimpleName() 获取类名
                                    //如果字符串的第二个字符非大写，则将字符串的第一个字符转换为小写 例 UserName -> userName
                                    //简单一点就是将类名改成beanName 形成驼峰命名
                                    beanName = Introspector.decapitalize(cls.getSimpleName());
                                }

                                // 生成 BeanDefinition，解析 单例bean or 多例bean
                                BeanDefinition beanDefinition = new BeanDefinition();
                                beanDefinition.setType(cls);
                                //这个类上方是否有@Scope
                                if (cls.isAnnotationPresent(Scope.class)) {
                                    Scope scopeAnnotation = cls.getAnnotation(Scope.class);
                                    beanDefinition.setScope(scopeAnnotation.value()); //有就按value中指定的值来
                                } else {
                                    beanDefinition.setScope("singleton"); //没有 默认创建的是单例bean
                                }
                                //将 beanDefinition 对象放入map集合中
                                beanDefinitionMap.put(beanName, beanDefinition);
                            }
                        } catch (Throwable e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            }
        }
        //System.out.println("<<<<<<<<<<<<<<<<<<<<<<");
    }

    /**
     * 创建所有 Bean 后处理器，放入 singletonObjects 容器中，并注册到 beanPostProcessorList
     * 在后续的 preInstantiateSingletons() 初始化单例中，会先从容器中获取，获取不到再创建
     * Bean 后处理器属于单例，提前创建好了并放入容器，所以 Bean 后处理器并不会重复创建
     */
    private void registerBeanPostProcessors() {
        //将常用的后处理器 直接放入BeanDefinition的Map集合中
        registerCommonBeanPostProcessor();
        /*
          1. 从 beanDefinitionMap 中找出所有的 BeanPostProcessor
          2. 创建 BeanPostProcessor 放入容器
          3. 将创建的 BeanPostProcessor 注册到 beanPostProcessorList

          这里的写法：先注册的 BeanPostProcessor 会对后创建的 BeanPostProcessor 进行拦截处理，
          BeanPostProcessor 的创建走 bean 的生命周期流程
         */
        this.beanDefinitionMap.entrySet()
                .stream()
                //A.isAssignableFrom(B)
                //确定一个类(B)是不是继承来自于另一个父类(A)，一个接口(A)是不是实现了另外一个接口(B)，或者两个类相同。
                .filter((entry) -> BeanPostProcessor.class.isAssignableFrom(entry.getValue().getType()))
                .forEach((entry) -> {
                    BeanPostProcessor beanPostProcessor = (BeanPostProcessor) getBean(entry.getKey());
                    this.beanPostProcessorList.add(beanPostProcessor);
                });
    }

    //将自动代理后处理器的BeanDefinition 放入Map集合中
    private void registerCommonBeanPostProcessor() {
        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setType(AnnotationAwareAspectJAutoProxyCreator.class);
        beanDefinition.setScope("singleton");
        beanDefinitionMap.put("internalAutoProxyCreator", beanDefinition);
    }

    // 将扫描到的单例 bean 创建出来放到单例池中
    private void preInstantiateSingletons() {
        beanDefinitionMap.forEach((beanName, beanDefinition) -> {
            if (beanDefinition.isSingleton()) {
                getBean(beanName);
            }
        });
    }

    /**
     * 创建 bean
     * createBean 方法就是在模拟 bean 的生命周期
     * 创建、依赖注入、初始化
     *
     */
    private Object createBean(String beanName, BeanDefinition beanDefinition) {
        //判断该bean是否正在创建：如果是:说明这次创建已经是第二次 并且第一次还没创建完 需要抛出异常
        beforeCreation(beanName, beanDefinition);
        try {
            // 创建对象
            Object bean = createBeanInstance(beanName, beanDefinition);

            // 如果当前创建的是单例对象，依赖注入前 将工厂对象存入三级缓存中
            if (beanDefinition.isSingleton()) {
                //System.out.println("向三级缓存中放入 该对象的工厂对象");
                this.singletonFactories.put(beanName, new ObjectFactory<Object>() {
                    @Override //这个方法不会立即执行 但是这些bean beanName会保存 等到需要调用时执行
                    public Object getObject() throws RuntimeException {
                        Object exposedObject = bean;
                        //遍历所有的Bean后处理器 找到SmartInstantiationAwareBeanPostProcessor后
                        //这个接口有一个实现类：就是自动代理后处理器。
                        //通过上面这个后处理器来返回代理对象或者工厂对象
                        for (BeanPostProcessor beanPostProcessor : ApplicationContext.this.beanPostProcessorList) {
                            if (beanPostProcessor instanceof SmartInstantiationAwareBeanPostProcessor) {
                                exposedObject = ((SmartInstantiationAwareBeanPostProcessor) beanPostProcessor).getEarlyBeanReference(exposedObject, beanName);
                            }
                        }
                        return exposedObject;
                    }
                });
                this.earlySingletonObjects.remove(beanName);
            }

            Object exposedObject = bean;
            //对该对象进行依赖注入
            populateBean(beanName, beanDefinition, bean);
            //对该对象执行初始化
            exposedObject = initializeBean(beanName, beanDefinition, exposedObject);

            // 去二级缓存 earlySingletonObjects 中查看有没有当前 bean，
            // 如果有，说明发生了循环依赖，返回缓存中的 a 对象（可能是代理对象也可能是原始对象，主要看有没有切点匹配到 bean）。
            if (beanDefinition.isSingleton()) {
                Object earlySingletonReference = getSingleton(beanName, false);
                if (earlySingletonReference != null) {
                    exposedObject = earlySingletonReference;
                }
            }
            //注册 disposable bean，注意注册的是原始对象，而不是代理对象 (就是将原始的bean对象放入可销毁Bean集合中)
            registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);

            return exposedObject;
        } catch (Throwable e) {
            throw new RuntimeException(e);
        } finally {
            afterCreation(beanName, beanDefinition);  //执行结束创建bean的流程
        }
    }
    //将原始的bean对象放入可销毁Bean集合中(不是代理对象,并且该对象为单例对象且实现了destroy()方法)
    private void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) {
        if (beanDefinition.isSingleton() && DisposableBeanAdapter.hasDestroyMethod(bean, beanDefinition)) {
            this.disposableBeans.put(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));
        }
    }
    //结束创建bean 后的流程：将该bean从 正在创建对象的集合中移除
    private void afterCreation(String beanName, BeanDefinition beanDefinition) {
        if (beanDefinition.isSingleton()) {
            afterSingletonCreation(beanName);
        } else {
            afterPrototypeCreation(beanName);
        }
    }
    //将多例对象从 正在创建多例对象的ThreadLocal 中移除
    @SuppressWarnings("unchecked")
    private void afterPrototypeCreation(String beanName) {
        Object curVal = this.prototypesCurrentlyInCreation.get();
        if (curVal instanceof String) {
            this.prototypesCurrentlyInCreation.remove();
        } else if (curVal instanceof Set) {
            Set<String> beanNameSet = (Set<String>) curVal;
            beanNameSet.remove(beanName);
            if (beanNameSet.isEmpty()) {
                this.prototypesCurrentlyInCreation.remove();
            }
        }
    }
    //单例对象创建完之后检查：
    // 1.这个创建完的对象是否被别的线程修改 导致正在创建的对象集合中没有该对象
    // 2.将这个对象从 正在创建的单例对象 集合中移除
    private void afterSingletonCreation(String beanName) {
        if (!this.singletonsCurrentlyInCreation.contains(beanName)) {
            // 可能被别的线程修改了
            throw new IllegalStateException(beanName + "':不在 正在创建的单例对象 集合中");
        }
        this.singletonsCurrentlyInCreation.remove(beanName); //最后将这个创建完的对象
    }
    //创建前的操作：判断该Bean是否已经正在创建
    private void beforeCreation(String beanName, BeanDefinition beanDefinition) {
        if (beanDefinition.isSingleton()) {
            beforeSingletonCreation(beanName); //判断该单例bean是否正在创建
        } else {
            beforePrototypeCreation(beanName); //判断多例bean是否正在创建
        }
    }
    //判断多例对象是否正在创建
    @SuppressWarnings("unchecked")  //不检测警告
    private void beforePrototypeCreation(String beanName) {
        Object curVal = this.prototypesCurrentlyInCreation.get();
        //判断这个ThreadLocal中是否有这个beanName
        if (curVal != null &&
                (curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName)))) {
            throw new IllegalStateException(beanName + "': 已经正在创建 还没创建完 你不能再创建");
        }
        //运行到这里表示这个多例对象之前没有正在创建 就加入ThreadLocal
        //如果这个ThreadLocal为空 就放入一个beanName
        //如果这个ThreadLocal有一个beanName 就创建一个set集合 存放这些beanName
        //如果这个ThreadLocal存放的是一个set集合 就将这个beanName放入set集合
        if (curVal == null) {
            this.prototypesCurrentlyInCreation.set(beanName);
        } else if (curVal instanceof String) {
            Set<String> beanNameSet = new HashSet<>();
            beanNameSet.add((String) curVal);
            beanNameSet.add(beanName);
            this.prototypesCurrentlyInCreation.set(beanNameSet);
        } else {
            Set<String> beanNameSet = (Set<String>) curVal;
            beanNameSet.add(beanName);
        }
    }
    //在单例对象创建前的操作：判断该对象是否正在创建 正在创建就报错 正在创建的Map中没有该key 就将其放入正在创建的行列中
    private void beforeSingletonCreation(String beanName) {
        if (this.singletonsCurrentlyInCreation.contains(beanName)) {
            throw new IllegalStateException(beanName+"：正在创建 请不要重复创建。导致原因：是不是因为出现循环依赖？");
        }
        this.singletonsCurrentlyInCreation.add(beanName);
    }

    /**
     * 初始化阶段，包含：Aware回调、初始化前、初始化、初始化后
     * 先执行Aware接口的回调 -> 执行 初始化前的后置处理器 -> 执行 InitializingBean接口的回调 -> 执行 初始化后的后置处理器(如创建代理)
     * 涉及知识点： 4种初始化方式的执行顺序：
     * Aware接口 > @PostConstruct > InitializingBean接口 > initMethod
     */
    private Object initializeBean(String beanName, BeanDefinition beanDefinition, Object bean) {
        // 0️⃣ 各种 Aware 回调
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) (bean)).setBeanName(beanName);
        }
        if (bean instanceof ApplicationContextAware) {
            ((ApplicationContextAware) (bean)).setApplicationContext(this);
        }

        // 1️⃣ 初始化前  执行初始化前的后置处理器
        // TODO  BeanPostProcessor 解析 @PostConstruct 执行初始化方法
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
            bean = beanPostProcessor.postProcessBeforeInitialization(bean, beanName);
        }

        // 2️⃣ 初始化  执行InitializingBean接口定义 的初始化方法
        if (bean instanceof InitializingBean) {
            ((InitializingBean) (bean)).afterPropertiesSet();
        }
        // TODO 执行 @Bean(initMethod = “myInit”) 指定的初始化方法（将初始化方法记录在 BeanDefinition 中）

        // 3️⃣ 初始化后，执行初始化后的后置处理器  如：AnnotationAwareAspectJAutoProxyCreator 创建 aop 代理
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
            bean = beanPostProcessor.postProcessAfterInitialization(bean, beanName);
        }
        // 如果有 aop 的话，这里的 bean 返回的是 aop 后的一个代理对象
        return bean;
    }

    /**
     * 依赖注入阶段，执行 bean 后处理器的 postProcessProperties 方法
     * 1. @AutoWired加在set方法上 ：从容器中获取参数 对应的对象,然后 执行set方法 实现依赖注入
     * 2. @AutoWired加在属性字段上 ：从容器中获取参数 对应的对象,然后将 该对象赋值给该属性 (没有走set方法)
     */
    private void populateBean(String beanName, BeanDefinition beanDefinition, Object bean) throws IllegalAccessException, InvocationTargetException {
        Class clazz = beanDefinition.getType();
        // 解析方法上的 Autowired
        for (Method method : clazz.getMethods()) {
            if (method.isAnnotationPresent(Autowired.class)) {
                // 编译时加上 -parameters 参数才能反射获取到参数名
                // 或者编译时加上 -g 参数，使用 ASM 获取到参数名
                //不然 获取到的参数名 都是 arg0,arg1...
                //为什么这里只获取一个参数？ 因为set方法不就一个参数嘛。。。
                String paramName = method.getParameters()[0].getName();
                method.invoke(bean, getBean(paramName));  //执行该方法
            }
        }
        // 解析字段上的 Autowired
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(Autowired.class)) {
                field.setAccessible(true); //因为有些字段被private修饰 通过该方法 关闭访问检查 就可以获取该属性
                // 去Spring 容器中找名为 field.getName() 的 bean，赋值给该属性  所以不会走set方法注入
                field.set(bean, getBean(field.getName()));
            }
        }

    }

    /*
        先将 beanDefinition 扫描出来再创建实例，而不是边扫描边创建
        是因为在 createBean 时，要进行依赖注入，需要看看有没有提供某个类的依赖
        所以要先扫描后创建
     */
    //preInstantiateSingletons()调用了该方法 将单例bean创建出来，然后放入单例池
    /*
        流程：
            1、如果是单例对象：去一级、二级、三级缓存中查询该对象 没有就创建
            2、如果是多例对象：创建一个对象出来
     */
    public Object getBean(String beanName) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition == null) {
            throw new NullPointerException();
        } else {
            // 单例
            if (beanDefinition.isSingleton()) {
                //去一级、二级、三级缓存中查询这个单例bean是否被创建
                Object singletonObject = getSingleton(beanName, true);
                // 三处缓存都没有某个 bean，只能 create
                if (singletonObject == null) {
                    singletonObject = createBean(beanName, beanDefinition);
                    this.singletonObjects.put(beanName, singletonObject);
                    this.earlySingletonObjects.remove(beanName); //以防万一，向二级缓存尝试remove该bean
                    this.singletonFactories.remove(beanName); //以防万一，向三级缓存尝试remove该bean
                }
                return singletonObject;
            } else { // 多例 就再创建一个
                return createBean(beanName, beanDefinition);
            }
        }
    }

    //将获取到的Bean 强制类型转换并返回 因为getBean(beanName) 方法返回的是Object
    public <T> T getBean(String beanName, Class<T> requiredType) {
        return (T) getBean(beanName);
    }

    /**
     * 尝试依次从 3 处缓存中取
        第二个参数 用来判断是否需要查询第三级缓存？因为getSingleTon会执行两遍 ：
        第一遍 是在getBean() 通过getSingleton(beanName,true)尝试从缓存中获取beanName对应的对象，没有才会创建 需要查看三级缓存
        第二遍 是在createBean() 通过getSingleton(beanName,false) 当创建完后查看二级缓存中是否有该对象的代理对象 不需要查看三级缓存
     */
    //TODO:这里synchronized+双重循环保证了三级缓存的线程安全
    private Object getSingleton(String beanName, boolean allowEarlyReference) {
        // 一级缓存： 单例池
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            // 二级缓存：提前创建的单例对象池
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                synchronized (this){
                    if (singletonObject == null && allowEarlyReference){
                        // 三级缓存：单例工厂池
                        ObjectFactory<?> objectFactory = this.singletonFactories.get(beanName);
                        if (objectFactory != null) {
                            //从三级缓存获取对象后，就将缓存从三级缓存中移除 放入二级缓存
                            singletonObject = objectFactory.getObject();
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
        }
        return singletonObject;
    }
    //获取所有的Bean的Class对象
    public List<Class<?>> getAllBeanClass() {
        return beanDefinitionMap.values()
                .stream()
                .map((Function<BeanDefinition, Class<?>>) BeanDefinition::getType)
                .collect(Collectors.toList());
    }
    //获取所有的Bean的Name
    public ArrayList<String> getBeanNames() {
        return new ArrayList<>(beanDefinitionMap.keySet());
    }
    //获取所有Bean的BeanDefinition
    public ArrayList<BeanDefinition> getBeanDefinition(){
        return new ArrayList<>(beanDefinitionMap.values());
    }
    /**
     * 创建 bean
     * 编译时加上 -parameters 参数才能反射获取到参数名
     * 或者编译时加上 -g 参数，使用 ASM 获取到参数名
     * 流程：
     *  1、优先使用无参构造
     *  2.没有无参构造 随机一个有参构造进行使用
     *      2.1 参数使用 BeanFactory 或者 @Lazy 都会触发延迟加载
     *      2.2 参数没有使用上述情况，直接调用getBean()方法获取
     */
    private Object createBeanInstance(String beanName, BeanDefinition beanDefinition) throws Throwable {
        Class<?> clazz = beanDefinition.getType();
        // 优先使用无参构造
        Constructor<?>[] constructors = clazz.getConstructors();
        for (Constructor<?> constructor : constructors) {
            if (constructor.getParameterCount() == 0) {
                return constructor.newInstance();
            }
        }
        // 没有无参构造，使用有参构造，随机选一个构造器
        Constructor<?> constructor = constructors[0];
        Object[] args = new Object[constructor.getParameterCount()];
        Parameter[] parameters = constructor.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            Object arg = null;
            if (parameter.getType().equals(ObjectFactory.class)) { // ObjectFactory 参数
                arg = buildLazyObjectFactory(parameter.getName());
            } else if (parameter.isAnnotationPresent(Lazy.class)) { // 参数加了 @Lazy，生成代理
                arg = buildLazyResolutionProxy(parameter.getName(), parameter.getType());
            } else { // 不是 ObjectFactory 也没加 @Lazy 的，直接从容器中拿
                arg = getBean(parameter.getName());
            }
            args[i] = arg;
        }
        return constructor.newInstance(args);
    }
    //如果是工厂对象 就延迟创建 等到调用getObject方法时再从容器中获取对象
    private Object buildLazyObjectFactory(String requestingBeanName) {
        return new ObjectFactory<Object>() {
            @Override
            public Object getObject() throws RuntimeException {
                return getBean(requestingBeanName);
            }
        };
    }
    //该参数使用@Lazy 创建代理对象
    private Object buildLazyResolutionProxy(String requestingBeanName, Class<?> clazz) {
        LazyInjectTargetSource targetSource = new LazyInjectTargetSource(this, requestingBeanName);
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTargetSource(targetSource);
        proxyFactory.setInterfaces(clazz.getInterfaces());
        // 临时的解决方案，JDK 动态代理只能基于接口，要代理的 class 可能本身是个接口，添加进去
        if (clazz.isInterface()) {
            proxyFactory.addInterface(clazz);
        }
        System.out.println("使用有参构造，为 " + requestingBeanName + " 参数创建代理对象");
        return proxyFactory.getProxy();
    }
    //关闭Spring容器
    public void close() {
        destroySingletons();
    }
    //执行所有可销毁Bean的销毁工作
    private void destroySingletons() {
        synchronized (this.disposableBeans) {
            Set<Map.Entry<String, Object>> entrySet = this.disposableBeans.entrySet();
            Iterator<Map.Entry<String, Object>> it = entrySet.iterator();
            while (it.hasNext()) {
                Map.Entry<String, Object> entry = it.next();
                String beanName = entry.getKey();
                DisposableBean bean = (DisposableBean) entry.getValue();
                try {
                    bean.destroy();
                } catch (Exception e) {
                    System.out.println("销毁这个bean：'" + beanName + "' 抛出异常：" + e);
                }
                it.remove();
            }
        }
        // 清空所有的缓存
        this.singletonObjects.clear();
        this.earlySingletonObjects.clear();
        this.singletonFactories.clear();
    }

    //对外提供销毁 bean 的方法
    public void destroyBean(String beanName, Object bean) {
        // beanDefinition 未处理
        new DisposableBeanAdapter(bean, beanName, null).destroy();
    }
    public void destroyBean(Object bean) {
        new DisposableBeanAdapter(bean, bean.getClass().getName(), null).destroy();
    }
}
